

#include <stdint.h>
#include <stdio.h>

#define  __ARM_TARGET_COPROC   0x5
#include <arm_acle.h>

#include "compiler.h"
#include "hcb_comn.h"
#include "sf.h"


/**/
#define  JKCMD_GETID		0x0E01
#define  JKCMD_PARAM		0x0D02
#define  JKCMD_ERASE		0x0C03
#define  JKCMD_READ			0x0B04
#define  JKCMD_PROG			0x0A05


/* mcpu --> jlink --> PC */
#define  JKCMD_ERROR		0x0EEE



/**/
extern  uint32_t  arm_dcc_read();
extern  void  arm_dcc_write( uint32_t data );

int  jkdcc_recv( uint16_t * pcmd, uint16_t * plen, void ** ppdat )
{
	uint32_t  i;
	uint32_t  temp;
	uint32_t  tlen;
	uint32_t  * pdat;
	static  uint8_t  tary[4096];

	/* cmd + length(word) */
	temp = arm_dcc_read();
	tlen = temp & 0xFFFF;
	if ( tlen > 1024 )
	{
		return 1;
	}

	/**/
	pdat = (uint32_t *)&( tary[0] );
	for ( i=0; i<tlen; i++ )
	{
		pdat[i] = arm_dcc_read();
	}

	/* data block */
	*pcmd = (uint16_t)(temp >> 16);
	*plen = (uint16_t)(tlen << 2);
	*ppdat = (void *)pdat;
	return 0;
}


int  jkdcc_send( uint16_t tcmd, uint16_t tlen, void * pdat )
{
	uint16_t  i;
	uint32_t  temp;
	uint32_t * pu32;

	/* align to 4 */
	tlen = (tlen + 3) >> 2;

	/**/
	temp = tcmd;
	temp = (temp << 16) | tlen;
	
	/**/
	arm_dcc_write( temp );

	if ( tlen > 0 )
	{
		pu32 = (uint32_t *)pdat;

		/**/
		for ( i=0; i<tlen; i++ )
		{
			arm_dcc_write( pu32[i] );
		}
	}

	/**/
	return 0;
}


int  nor_flash_init( uint32_t spage, uint32_t sblck );
int  nor_flash_unlock( void );
int  nor_flash_page_read( uint32_t faddr, uint8_t *buf );
int  nor_flash_page_prog( uint32_t faddr, uint8_t *buf );
int  nor_flash_sector_erase( uint32_t faddr );



int  jksf_getid( uint16_t tlen, void * pdat )
{
	uint32_t  temp;
	
	/**/
	temp = sf_hw_get_id();

	/**/
	jkdcc_send( JKCMD_GETID, sizeof(temp), &temp );
	printf( "send, ok\n" );
	return 0;
}



static uint32_t  spage = 0;
static uint32_t  sblck = 0;

/*
uint32_t : block, bytes
uint32_t : page, bytes
*/
int  jksf_param( uint16_t tlen, void * pdat )
{
	int  iret;
	uint32_t * pu32;

	if ( tlen < 8 )
	{
		printf( "param, len=%d\n", tlen );
		jkdcc_send( JKCMD_ERROR, 0, NULL );
		return 0;
	}

	pu32 = (uint32_t *)pdat;
	spage = pu32[0];
	sblck = pu32[1];
	printf( "param, 0x%X, 0x%x\n", spage, sblck );

	/**/
	iret = nor_flash_init( spage, sblck );
	if ( iret != 0 )
	{
		jkdcc_send( JKCMD_ERROR, 0, NULL );
		return 0;
	}

	iret = nor_flash_unlock();
	if ( iret != 0 )
	{
		jkdcc_send( JKCMD_ERROR, 0, NULL );
		return 0;
	}
	
	/**/
	jkdcc_send( JKCMD_PARAM, 0, NULL );
	return 0;
}


/*
*/
int  jksf_read( uint16_t tlen, void * pdat )
{
	int  iret;
	uint32_t * pu32;
	uint32_t  sttp;
	uint32_t  cntp;
	uint32_t  i;
	uint32_t  temp;
	uint8_t  tary[2048];

	if ( tlen < 8 )
	{
		printf( "read, len=%d\n", tlen );
		jkdcc_send( JKCMD_ERROR, 0, NULL );
		return 0;
	}

	/**/
	pu32 = (uint32_t *)pdat;
	sttp = pu32[0];
	cntp = pu32[1];

	printf( "read, 0x%X, 0x%x\n", sttp, cntp );

	/**/
	for ( i=0; i<cntp; i++ )
	{
		iret = nor_flash_page_read( ( sttp + i ) * spage, tary );
		if ( iret != 0 )
		{
			printf( "read, fail, %d, %d\n", i, iret );
			jkdcc_send( JKCMD_ERROR, 0, NULL );
		}

		/**/
		jkdcc_send( JKCMD_READ, spage, tary );
	}
	
	return 0;
}


/*
 req : blk_idx, count
resp : na
*/
int  jksf_erase( uint16_t tlen, void * pdat )
{
	int  iret;
	uint32_t * pu32;
	uint32_t  sttblk;
	uint32_t  cntblk;
	uint32_t  i;

	/**/
	if ( tlen < 8 )
	{
		printf( "erase, len=%d\n", tlen );
		jkdcc_send( JKCMD_ERROR, 0, NULL );
		return 0;
	}

	/**/
	pu32 = (uint32_t *)pdat;
	sttblk = pu32[0];
	cntblk = pu32[1];
	printf( "erase, 0x%X, 0x%x\n", sttblk, cntblk );

	/**/
	for ( i=0; i<cntblk; i++ )
	{
		iret = nor_flash_sector_erase( (sttblk + i ) * sblck );
		if ( iret != 0 )
		{
			jkdcc_send( JKCMD_ERROR, 0, NULL );
			return 0;
		}
		
		/**/
		jkdcc_send( JKCMD_ERASE, 0, NULL );
	}

	return 0;
}



int  jksf_prog( uint16_t tlen, void * pdat )
{
	int  iret;
	uint32_t * pu32;
	uint32_t  sttp;
	uint32_t  cntp;
	uint32_t  i;

	if ( tlen < 8 )
	{
		printf( "prog, len=%d\n", tlen );
		jkdcc_send( JKCMD_ERROR, 0, NULL );
		return 0;
	}

	/**/
	pu32 = (uint32_t *)pdat;
	sttp = pu32[0];
	cntp = pu32[1];

	printf( "prog, 0x%X, 0x%x\n", sttp, cntp );	
	
	/* zero resp */
	jkdcc_send( JKCMD_PROG, 0, NULL );

	/**/
	for ( i=0; i<cntp; i++ )
	{
		uint16_t  tcmd;
		uint16_t  tlen;
		uint8_t * pdat;

		/* recv */
		iret = jkdcc_recv( &tcmd, &tlen, (void **)&pdat );
		if ( iret != 0 )
		{
			return 1;
		}

		/* check args */
		if ( tcmd != JKCMD_PROG )
		{
			jkdcc_send( JKCMD_ERROR, 0, NULL );
			return 2;
		}

		if ( (uint32_t)tlen != spage )
		{
			jkdcc_send( JKCMD_ERROR, 0, NULL );
			return 3;
		}

		iret = nor_flash_page_prog( ( sttp + i ) * spage, pdat );
		if ( iret != 0 )
		{
			printf( "prog, fail, %d, %d\n", i, iret );
			jkdcc_send( JKCMD_ERROR, 0, NULL );
			return 4;
		}

		/**/
		jkdcc_send( JKCMD_PROG, 0, NULL );
	}

	return 0;
}



int  main( void )
{
	int  iret;
	uint16_t   tcmd;
	uint16_t   tlen;
	void * pdat;

	/* clean DCC channel */
    __arm_mrc( 14, 0, 0, 5, 0 );	
	
    /* sysctrl, switch to 400Mhz */
    // write_reg( BASE_AP_SYSCTL + 0x44,  1 );
	printf(">>>>hello>>\n");

	/* sfc, init */
	sf_reset();
	sf_set_div( 8 );

	/* todo : reset flash chip,  0x66, 0x99. */

	/**/
    while (1 )
    {
		iret = jkdcc_recv( &tcmd, &tlen, &pdat );
		if ( iret != 0 )
		{
			/**/
			printf( "dcc recv, %d\n", iret );
			continue;
		}
		
		printf( "cmd, %x, %d\n", tcmd, tlen );

		/**/
		switch ( tcmd )
		{
		case JKCMD_GETID:
			jksf_getid( tlen, pdat );
			break;
		
		case JKCMD_PARAM:
			jksf_param( tlen, pdat );
			break;
		
		case JKCMD_READ:
			jksf_read( tlen, pdat );
			break;

		case JKCMD_ERASE:
			jksf_erase( tlen, pdat );
			break;

		case JKCMD_PROG:
			jksf_prog( tlen, pdat );
			break;

		default:
			break;
		}
    }

    return 0;
}



